
package io.renren.utils.util.db.transaction;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;


public abstract class BaseTransaction implements Transaction {

    // ----------------------------------------------------- Static Variables
    static Logger logger = Logger.getLogger(BaseTransaction.class.getName());

    // ----------------------------------------------------- Instance Variables
    private Map transactions, transactionsToCommit;
    private String name = null;
    
    // ----------------------------------------------------------- Constructors
    BaseTransaction(String name) {
        this();
        setName(name);
    }

    BaseTransaction() {
        transactions = new HashMap();
        transactionsToCommit = new TreeMap();
    }

    // ------------------------------------------------------------- Properties
    /**
     * Get the value of the Transaction name.
     * @return value of name.
     */
    public String getName() {
        return name;
    }

    /**
     * Set the value of the Transaction name.
     * @param name  Value to assign to name.
     */
    public void setName(String name) {
        this.name = name;
    }


    // --------------------------------------------------------- Public Methods
    /**
     * Get the value of priority.
     * @return value of priority.
     */
    public int getPriority() {
	return NORMAL_PRIORITY;
    }
    
    /**
     * Implemented from com.gsol.enigma.business.persist.Transaction:
     * Commit changes done to the Transactions in this BaseTransaction
     */
    public void commit() throws TransactionException {
        // commit for all the Transactions in this BaseTransaction
        if (logger.isDebugEnabled()) {
        		logger.debug("Calling commit for TX 11- " + getName() + " at " + hashCode());
        }

        Iterator iterator = getTransactionsToCommit().iterator();
        while (iterator.hasNext()) {
            Transaction tx = (Transaction) iterator.next();
            if (logger.isEnabledFor(Level.DEBUG)) {
            	if (tx instanceof DBTransaction) {
            		io.renren.utils.util.db.connection.DBConnection c = (io.renren.utils.util.db.connection.DBConnection)((DBTransaction)tx).getConnection();
            		logger.debug("Calling commit for TX 22 - " + c.getPoolName() + " at " + tx.hashCode() + " in " + getName() + " at " + c);
            	} else {
            		logger.debug("Calling commit for TX 33- " + tx.getName() + " at " + tx.hashCode() + " in " + getName() + " at " + hashCode());
            	}
            }
            tx.commit();
            iterator.remove();
            tx = null;
        }
        if (logger.isDebugEnabled())
            logger.debug("Done with commit for TX - " + getName() + " at " + hashCode());

    }

    /**
     * Implemented from com.gsol.enigma.business.persist.Transaction:
     * Rollback changes done to the Transactions in this BaseTransaction
     */
    public void rollback() throws TransactionException {
        if (logger.isDebugEnabled())
            logger.debug("Calling rollback for TX - " + getName() + " at " + hashCode());

        // rollback for all the Transactions in this BaseTransaction
        Iterator iterator = transactions.values().iterator();
        while (iterator.hasNext()) {
            Transaction tx = (Transaction) iterator.next();
            tx.rollback();
        }
        if (logger.isDebugEnabled())
            logger.debug("Done with rollback for TX - " + getName() + " at " + hashCode());

    }


    /**
     * Implemented from com.gsol.enigma.business.persist.Transaction:
     * Add a Transaction (Unit Of Work) to this BaseTransaction.
     *
     * @param tx The Transaction to be added
     */
    public void addTransaction(Transaction tx) {
        if (!transactions.containsKey(tx.getName())) {
            if (logger.isEnabledFor(Level.DEBUG))
                logger.debug("Added transaction " + tx.getName() + " at " + tx.hashCode() + " for " + getName() + " at " + hashCode());
            transactions.put(tx.getName(), tx);

	    // put the tx into a sorted map based on its priority value
	    addTransactionToCommitQueue(tx);
        }
        else {
            if (logger.isEnabledFor(Level.DEBUG))
                logger.debug("Transaction [" + tx.getName() + "] at " + tx.hashCode() + " already exists");
        }
    }


    /**
     * Implemented from com.gsol.enigma.business.persist.Transaction:
     * Get a Transaction (Unit Of Work) from this BaseTransaction
     *
     * @param name Name of the Transaction requested
     * @return Transaction requested
     */
    public Transaction getTransaction(String name) {
        Transaction retVal = null;
        if (transactions.containsKey(name)) {
            retVal = (Transaction) transactions.get(name);
        }
        else {
            if (logger.isEnabledFor(Level.DEBUG))
                logger.debug("Transaction object [" + name + "] not found in [" + this.getName() + "] at " + hashCode());
        }

        return retVal;
    }

    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append(getName() + "[");
        Iterator iterator = transactions.values().iterator();
        while (iterator.hasNext()) {
            Transaction tx = (Transaction) iterator.next();
            buf.append(tx.toString() + ",");
        }
        buf.append("]");
        return buf.toString();
    }

    // ----------------------------------------------------- helping methods
    void addTransactionToCommitQueue(Transaction tx) {
	Integer priority = new Integer(tx.getPriority());
	List curTxs = (List) transactionsToCommit.get(priority);
	if (curTxs == null) {
	    curTxs = new ArrayList();
	    transactionsToCommit.put(priority, curTxs);
	}
	curTxs.add(tx);
    }

    List getTransactionsToCommit() {
	List retVal = new ArrayList();
	for (Iterator iter=transactionsToCommit.values().iterator(); iter.hasNext();) {
	    retVal.addAll((List) iter.next());
	}
	return retVal;
    }

}// BaseTransaction


